package be.castanea.client.util;

import java.io.File;
import java.util.ArrayList;

import com.jme.scene.Node;
import com.jme.scene.PassNode;
import com.jme.system.DisplaySystem;
import com.jmex.terrain.TerrainPage;
import com.mw3d.terrain.brushes.PaintBrush;
import com.mw3d.terrain.event.TerrainLayerListener;
import com.mw3d.terrain.model.TerrainAlphaLayer;
import com.mw3d.terrain.model.TerrainBaseLayer;
import com.mw3d.terrain.model.TerrainLayer;

/**
 * Simple splat manager to create layers on the system, this class works with out the need for
 * the world context from the editor.
 * @author Tareq doufish
 */
public class SimpleSplatManager {

    /** The splat node that we are using */
    protected PassNode splattingPassNode;
    /** The base layer */
    private TerrainBaseLayer baseLayer;
    /** Array list of textures that users can draw with */
    private ArrayList<TerrainLayer> terrainLayers = new ArrayList<TerrainLayer>();
    private ArrayList<TerrainLayerListener> terrainLayerListeners = new ArrayList<TerrainLayerListener>();
    /** Terrain page */
    private TerrainPage page;
    /** The scene node */
    private Node sceneNode;

    public SimpleSplatManager(TerrainPage page, Node sceneNode) {
        this.page = page;
        this.sceneNode = sceneNode;
    }

    public TerrainBaseLayer getBaseLayer() {
        return baseLayer;
    }
    private Node mainTerrainNode;

    public Node getMainTerrainNode() {
        if (mainTerrainNode == null && page != null) {
            return page.getParent();
        }
        return mainTerrainNode;
    }

    public PassNode getTerrainPassNode() {
        if (splattingPassNode == null) {
            this.mainTerrainNode = page.getParent();
            page.setDetailTexture(1, 1);
            splattingPassNode = new PassNode("SplatPassNode");
            splattingPassNode.attachChild(page);
            sceneNode.attachChild(splattingPassNode);

            splattingPassNode.lockBounds();
            splattingPassNode.lockTransforms();
            splattingPassNode.lockShadows();
        } else {
            if (splattingPassNode.getChildren() != null && splattingPassNode.getChildren().size() == 0) {
                this.mainTerrainNode = page.getParent();
                page.setDetailTexture(1, 1);
                splattingPassNode = new PassNode("SplatPassNode");
                splattingPassNode.attachChild(page);
                sceneNode.attachChild(splattingPassNode);

                splattingPassNode.lockBounds();
                splattingPassNode.lockTransforms();
                splattingPassNode.lockShadows();
            }
        }
        return splattingPassNode;
    }

    public PassNode getSplatNode() {
        return splattingPassNode;
    }

    public void removeLayer(TerrainLayer layer) {
        this.terrainLayers.remove(layer);

        notifyTerrainLayerRemoved(layer);
    }

    public ArrayList<TerrainLayer> getTerrainLayers() {
        return this.terrainLayers;
    }

    public ArrayList<TerrainAlphaLayer> getTerrainAlphaLayers() {
        ArrayList<TerrainAlphaLayer> layers = new ArrayList<TerrainAlphaLayer>();
        for (TerrainLayer layer : terrainLayers) {
            if (layer instanceof TerrainAlphaLayer) {
                layers.add((TerrainAlphaLayer) layer);
            }
        }
        return layers;
    }

    public void addTerrainLayer(TerrainLayer terrainLayer) {
        this.terrainLayers.add(terrainLayer);

        notifyTerrainLayerAdded(terrainLayer);
    }

    public void notifyTerrainLayerAdded(TerrainLayer terrainLayer) {
        for (TerrainLayerListener l : terrainLayerListeners) {
            l.terrainLayerAdded(terrainLayer);
        }
    }

    public void notifyTerrainLayerRemoved(TerrainLayer terrainLayer) {
        for (TerrainLayerListener l : terrainLayerListeners) {
            l.terrainLayerRemoved(terrainLayer);
        }
    }

    public void notifyLayersOrderChanged(TerrainLayer one, TerrainLayer two) {
        for (TerrainLayerListener l : terrainLayerListeners) {
            l.orderChanged(one, two);
        }
    }

    public void notifyActiveLayerChanged(TerrainLayer one) {
        for (TerrainLayerListener l : terrainLayerListeners) {
            l.activeLayerChanged(one);
        }
    }

    public void addTerrainLayerListener(TerrainLayerListener l) {
        this.terrainLayerListeners.add(l);
    }

    public void removeTerrainLayerListener(TerrainLayerListener l) {
        this.terrainLayerListeners.remove(l);
    }

    /**
     * Registers the terrain layer to the splat manager here.
     * @param layer
     */
    public void registerBaseLayer(TerrainBaseLayer layer) {
        layer.setPassNode(getTerrainPassNode());
        layer.addToPassNode();
        addTerrainLayer(layer);
        this.baseLayer = layer;
    }

    public TerrainBaseLayer createBaseFromFile(File file, float uScale, float vScale) {
        baseLayer = new TerrainBaseLayer(file.getPath(), DisplaySystem.getDisplaySystem().getRenderer());
        baseLayer.setPassNode(getTerrainPassNode());
        baseLayer.addToPassNode();
        addTerrainLayer(baseLayer);

        baseLayer.setUValue(uScale);
        baseLayer.setVValue(vScale);
        return baseLayer;
    }

    public void registerAlphaLayer(TerrainAlphaLayer layer) {
        PaintBrush brush = new PaintBrush(layer.getBaseTextureUrl(), layer.getAlphaTextureUrl());
        brush.loadBrushTexture();

        // creating the base layer here.
        layer.setBlendTexture(brush.getDrawTexture().getTexture());
        layer.setTextureImage(brush.getDrawTexture().getAwtImage());

        layer.setBrush(brush);

        addTerrainLayer(layer);
        layer.setPassNode(getTerrainPassNode());
        layer.getPassNodeTextureState();
        layer.addToPassNode();

    }

    public TerrainAlphaLayer createAlphaFromFile(File textureFile, File alphaFile, float uScale, float vScale) {
        PaintBrush brush = new PaintBrush(textureFile.getPath(), alphaFile.getPath());
        brush.loadBrushTexture();

        // creating the base layer here.
        TerrainAlphaLayer layer = new TerrainAlphaLayer(textureFile.getPath(), alphaFile.getPath(), DisplaySystem.getDisplaySystem().getRenderer(), brush.getDrawTexture().getTexture());
        layer.setTextureImage(brush.getDrawTexture().getAwtImage());

        layer.setBrush(brush);

        addTerrainLayer(layer);
        layer.setPassNode(getTerrainPassNode());
        layer.getPassNodeTextureState();
        layer.addToPassNode();


        layer.setUValue(uScale);
        layer.setVValue(vScale);
        return layer;
    }
} 
